package nachos.network;
import java.util.LinkedList;

import nachos.machine.Lib;
import nachos.threads.*;

public class ExtendedSynchList extends SynchList{

	//we want to make it act similar to a linked list
	
	ExtendedSynchList(){
		list = new LinkedList<Object>();
		lock = new Lock();
		iterateLock = new Lock();
		count = 0;
		listEmpty = new Condition(lock);
	}
	
	public void add(Object o) {
		Lib.assertTrue(o != null);
		lock.acquire();
		list.add(o);
		listEmpty.wake();
		lock.release();
	}
	//removes the first element/object in the list 
	public Object pop() {
		Object o;
		lock.acquire();
		while (list.isEmpty())
			listEmpty.sleep();
		o = list.removeFirst();
		count--;
		lock.release();
		return o;
	}
	//acquires the first element of the list (does not remove it)
	public Object getFirst(){
		Object o = null;
		lock.acquire();
		if(!list.isEmpty())
				o = list.getFirst();
		lock.release();
		return o;
	}
	
	public void eraseFront(){
		lock.acquire();
		count--;
		list.removeFirst();
		lock.release();
	}
	
	//used to acquire a lock and iterate through the first object
	//count should be 0 (or less than 0) whenever this method is called and it should return
	//the first object in the list
	//this is used to ensure that an group of iterate calls can be made atomic
	public Object beginIterate(){
		iterateLock.acquire();
		return iterate();
	}
	
	//returns the next object in the list
	//is atomic in of itself, but multiple calls of it are not gaurunteed not to be interupted
	//unless you acquire the iterateLock
	public Object iterate(){
		Object found = null;
		lock.acquire();
		if(count < 0 )
				count = 0;
		if(!list.isEmpty() && count < list.size())
				found = list.get(count);
		lock.release();
		count++;
		return found;
	}
	
	public int getSize(){return list.size();}
	
	public void remove(){
		list.remove(count - 1);
		count--;
	}
	
	//releases iterate lock and resets count to 0
	//signifies that you have finished iterating (either reached the end or found
	//whatever it was being looked for)
	public void endIterate(){
		iterateLock.release();
		count = 0;
	}
	
	public boolean isEmpty(){
		return list.isEmpty();
		
	}
	
	private int count;
	private LinkedList<Object> list;
	private Lock lock;
	private Lock iterateLock;
	private Condition listEmpty;
}
